Коллекция Bash-скриптов для управления Docker/Podman-образами и их статического анализа безопасности. Скрипты покрывают полный цикл работы с образами — от скачивания и упаковки до аудита безопасности и отображения отчётов об уязвимостях.
Автор: Aleksei Blinov
- Обзор скриптов
- Общие зависимости
- images-load.sh — загрузка образов из .tar
- images-save.sh — сохранение образов в .tar
- json-report-pretty.sh — читаемый вывод отчётов уязвимостей
- rootless-docker-audit.sh — аудит rootless Docker
- image-security-checker.sh — статическая проверка безопасности образов
| Скрипт | Назначение | Инструмент |
|---|---|---|
images-load.sh |
Загрузка образов из .tar, перетеггирование и опциональный push в реестр |
docker / podman |
images-save.sh |
Pull образов для заданной платформы и сохранение в .tar |
docker |
json-report-pretty.sh |
Цветной вывод JSON-отчётов Trivy и Grype с фильтрацией по уровню | jq, column |
rootless-docker-audit.sh |
Комплексный аудит rootless-установки Docker | docker |
image-security-checker.sh |
Статический анализ безопасности Docker-образов | docker, tar |
| Зависимость | Используется в |
|---|---|
docker |
images-save, rootless-docker-audit, image-security-checker |
docker или podman |
images-load |
jq |
json-report-pretty |
column |
json-report-pretty |
tar |
image-security-checker |
awk |
image-security-checker |
stat |
image-security-checker |
pgrep, ps, lsns, unshare |
rootless-docker-audit |
Установка утилит на Debian/Ubuntu:
sudo apt install jq util-linuxЗагружает Docker/Podman-образы из .tar-файлов в указанном каталоге. Опционально перетеггирует каждый образ с новым префиксом реестра и предлагает запушить результат.
Скрипт автоматически определяет доступный инструмент — docker или podman.
Images Load/images-load.sh
dockerилиpodman
./images-load.sh <путь_к_каталогу_с_tar> [целевой_префикс]
| Аргумент | Обязательный | Описание |
|---|---|---|
путь_к_каталогу |
Да | Каталог, содержащий .tar-файлы образов |
целевой_префикс |
Нет | Префикс реестра для перетеггирования (registry.example.com/myproject) |
Загрузка образов без переименования:
./images-load.sh /opt/imagesЗагрузка с перетеггированием и push в реестр:
./images-load.sh /opt/images registry.example.com/myprojectПосле перетеггирования скрипт спросит подтверждение перед push:
👉 Запушить переименованные образы в реестр 'registry.example.com/myproject'? [Y/n]:
- Итерирует все
.tar-файлы в указанном каталоге. - Если
целевой_префиксзадан: для каждого загруженного образа вычисляет новый тег вида<prefix>/<name>:<tag>и добавляет его черезtag. - Если
целевой_префиксне задан: образы загружаются с оригинальными тегами без переименования. - Если в каталоге нет
.tar-файлов, скрипт завершается с предупреждением без ошибки.
Скачивает Docker-образы для указанной платформы и сохраняет их как .tar-архивы в текущем каталоге. Принимает образы как аргументы командной строки или из файла со списком.
Images Save/images-save.sh
docker
./images-save.sh [-p platform] image1 [image2 ...]
./images-save.sh [-p platform] -f image_list.txt
| Опция | По умолчанию | Описание |
|---|---|---|
-p platform |
linux/amd64 |
Целевая платформа (linux/arm64, linux/amd64 и т.д.) |
-f image_list.txt |
— | Файл со списком образов, по одному на строку |
Сохранение одного образа для платформы по умолчанию:
./images-save.sh nginx:1.25Сохранение нескольких образов для ARM:
./images-save.sh -p linux/arm64 nginx:1.25 redis:7 postgres:15Сохранение образов из файла:
./images-save.sh -f images.txtФормат файла images.txt:
# Это комментарий — строка игнорируется
nginx:1.25
redis:7
postgres:15
- Пустые строки и строки, начинающиеся с
#, в файле-списке пропускаются. - Имя результирующего архива формируется из имени образа заменой
/и:на_. Например,registry.example.com/myapp:v1.0сохраняется какregistry.example.com_myapp_v1.0.tar. - При ошибке во время
docker pullилиdocker saveскрипт завершается немедленно (set -e).
Читаемо отображает JSON-отчёты сканеров уязвимостей Trivy и Grype в терминале с цветовой подсветкой по уровню серьёзности и опциональной фильтрацией.
JSON Report Pretty/json-report-pretty.sh
jqcolumn
./json-report-pretty.sh <report.json> [--min-severity=LEVEL]
| Аргумент / Опция | По умолчанию | Описание |
|---|---|---|
report.json |
— | Путь к JSON-файлу отчёта Trivy или Grype |
--min-severity=LEVEL |
LOW |
Минимальный уровень серьёзности для отображения |
Допустимые значения --min-severity (от наиболее к наименее серьёзному):
CRITICAL HIGH MEDIUM LOW NEGLIGIBLE UNKNOWN
Отобразить все уязвимости из отчёта Trivy:
./json-report-pretty.sh trivy-report.jsonОтобразить только CRITICAL и HIGH:
./json-report-pretty.sh trivy-report.json --min-severity=HIGHОтобразить отчёт Grype только с CRITICAL:
./json-report-pretty.sh grype-report.json --min-severity=CRITICALСоздать отчёт Trivy и сразу передать его на отображение:
trivy image --format json -o report.json nginx:latest
./json-report-pretty.sh report.json --min-severity=MEDIUMTrivy — столбцы: CVE ID, пакет, версия, уровень, название:
CVE-2024-1234 openssl 3.0.2 CRITICAL Buffer overflow in TLS handshake
CVE-2024-5678 zlib 1.2.11 HIGH Integer overflow in inflate
Grype — столбцы: CVE ID, пакет, версия, уровень, EPSS, Risk score:
CVE-2024-1234 openssl 3.0.2 CRITICAL 0.00521 0.0031
| Уровень | Цвет |
|---|---|
| CRITICAL | Красный |
| HIGH | Жёлтый |
| MEDIUM | Синий |
| LOW | Зелёный |
| NEGLIGIBLE / UNKNOWN | Серый |
- Автоматически определяет формат отчёта по наличию ключа
.Results(Trivy) или.matches(Grype). - Если уязвимостей заданного уровня не найдено, выводит подтверждающее сообщение и завершается с кодом
0. - Если формат не распознан, завершается с ошибкой и кодом
1.
Проводит комплексный аудит rootless-установки Docker и выводит итоговую таблицу с результатами каждой проверки.
Rootless Docker Audit/rootless-docker-audit.sh
docker- Стандартные утилиты:
pgrep,ps,stat,grep,uname,awk,lsns,unshare
./rootless-docker-audit.sh
Скрипт не принимает позиционных аргументов. Поддерживается флаг -h / --help.
| # | Проверка | Что именно проверяется |
|---|---|---|
| 0 | Пользователь dockerd | dockerd запущен не от root; скрипт выполняется тем же пользователем |
| 1 | CONFIG_USER_NS | Наличие CONFIG_USER_NS=y в конфиге ядра /boot/config-$(uname -r) |
| 2 | subuid / subgid | Записи для текущего пользователя в /etc/subuid и /etc/subgid |
| 3 | Вспомогательные утилиты | Наличие slirp4netns, fuse-overlayfs, newuidmap, newgidmap |
| 4 | cgroup | Тип файловой системы /sys/fs/cgroup/ (ожидается cgroup2fs) |
| 5 | User namespace | Успешное создание namespace через unshare -Ur true |
| 5.1 | User namespace (lsns) | Наличие user namespace в lsns |
| 6 | docker info | SecurityOptions содержит rootless; корректность DOCKER_HOST |
| 7 | Окружение и сокеты | XDG_RUNTIME_DIR установлен; docker.sock доступен по этому пути |
| 8 | Сокеты dockerd | Наличие сокетов в /run/user/<uid>/docker.sock и $XDG_RUNTIME_DIR/docker.sock |
| 9 | Права файлов | Права на /etc/subuid и /etc/subgid не превышают 644 |
| 10 | Переменные окружения | DOCKER_DRIVER, DOCKER_ROOTLESS_ROOTLESSKIT_PORT_DRIVER |
🔍 Rootless Docker Audit Script
👤 Текущий пользователь: alice
🧠 Ядро: 6.1.0-21-amd64
--------------------------------------------
[0] Проверка пользователя dockerd:
✅ dockerd запущен без root (rootless mode)
[1] Проверка CONFIG_USER_NS:
✅ CONFIG_USER_NS включён
...
--------------------------------------------
📋 Итоговая таблица аудита:
[OK] dockerd запущен без root (rootless mode)
[OK] CONFIG_USER_NS включён
[FAIL] fuse-overlayfs не найден
--------------------------------------------
- Завершается немедленно с итоговой таблицей, если
dockerdне запущен или работает отroot. - Если обнаружены предупреждения или ошибки, в конце выводится раздел рекомендаций с конкретными действиями по устранению.
- Каждый результат помечается
[OK],[WARN]или[FAIL]и сохраняется для итоговой таблицы.
Выполняет статическую проверку безопасности Docker-образов без запуска контейнеров. Образ экспортируется как файловая система и анализируется набором проверок. Поддерживает проверку одного образа или списка из файла.
Image Security Checker/image-security-checker.sh
dockertarawkstat
./image-security-checker.sh <имя_образа>
./image-security-checker.sh -f <файл_со_списком>
| Аргумент | Описание |
|---|---|
<имя_образа> |
Имя или ID Docker-образа (локального или доступного для pull) |
-f <файл> |
Файл со списком образов, по одному на строку; пустые строки и #-комментарии пропускаются |
Проверка одного образа:
./image-security-checker.sh nginx:1.25Проверка нескольких образов из файла:
./image-security-checker.sh -f images.txtФормат файла images.txt:
# продакшн образы
nginx:1.25
myapp:v2.3.1
# базовые образы
registry.example.com/base:latest
| # | Проверка | Критерий прохождения |
|---|---|---|
| 1 | Пользователь по умолчанию | USER задан и не равен root или 0; UID/GID пользователя не равны 0 |
| 2 | Базовый дистрибутив | ОС из /etc/*-release — Red OS, Astra Linux или ALT Linux |
| 3 | Distroless | Отсутствуют: sh/bash/dash, apt/yum/dnf/apk, curl/wget, busybox |
| 4 | SUID/SGID файлы | Нет файлов с битом SUID (-4000) или SGID (-2000) |
| 5 | su / sudo | Нет исполняемых файлов su или sudo в образе |
| 6 | ENTRYPOINT/CMD от root | Стартовый процесс запускается не от root/0 |
| 7 | Права чувствительных каталогов | Права на /etc, /var, /root, /home не превышают 755 |
| 8 | Чувствительные файлы | Нет файлов .npmrc, .gitconfig, id_rsa в образе |
============================================
Проверка Docker-образа: nginx:1.25
============================================
[FAIL] USER по умолчанию не задан или равен root/0
[FAIL] Базовый дистрибутив не Red OS / Astra Linux / ALT. Найдено: ID=debian
[WARN] Образ не похож на distroless, найдено:
Найдены shell-утилиты:
/bin/bash
/bin/sh
[OK] Файлы с SUID отсутствуют
[OK] Файлы с SGID отсутствуют
[FAIL] ENTRYPOINT (/docker-entrypoint.sh nginx -g daemon off;) запускается под root
[OK] Каталог /etc разрешения: 755
[OK] Чувствительные файлы не найдены
- Для каждого образа создаётся временный контейнер (
docker create), файловая система которого экспортируется черезdocker exportиtarво временный каталог. - Временный контейнер и рабочий каталог удаляются автоматически при завершении скрипта (в том числе при ошибке) через
trap cleanup EXIT. - Если базовый дистрибутив распознан как российская ОС (Red OS / Astra Linux / ALT), проверка distroless выдаёт
[WARN]вместо[FAIL], поскольку наличие пакетного менеджера допустимо для таких образов. - Образы обрабатываются последовательно; сбой проверки одного образа не прерывает обработку остальных.
Проект принимает улучшения через pull request. Ниже описаны правила, которых следует придерживаться.
- Сделайте форк репозитория.
- Создайте ветку от
mainс именем по соглашению (см. ниже). - Внесите изменения, убедитесь что скрипты работают и проходят проверки.
- Откройте pull request в ветку
mainоригинального репозитория с понятным описанием того, что изменилось и зачем.
| Префикс | Когда использовать |
|---|---|
feature/ |
Новый скрипт или новая функциональность существующего |
fix/ |
Исправление ошибки или некорректного поведения |
chore/ |
Обновление зависимостей, конфигурации, документации без изменения логики |
Примеры:
feature/add-network-policy-checker
fix/rootless-audit-false-positive
chore/update-readme-usage-examples
Используется стиль Conventional Commits. Сообщение пишется на русском языке.
<тип>: <краткое описание в повелительном наклонении>
Допустимые типы:
| Тип | Назначение |
|---|---|
feat |
Новая функциональность |
fix |
Исправление ошибки |
chore |
Вспомогательные задачи, рефакторинг без изменения поведения |
docs |
Изменения только в документации |
Примеры:
feat: добавить проверку привилегированных контейнеров
fix: исправить парсинг JSON-отчёта при пустом входе
chore: убрать дублирующиеся проверки в аудите rootless
docs: добавить примеры использования в README
- Каждый скрипт должен начинаться с
set -euo pipefailсразу после шебанга. - Перед отправкой PR запустите ShellCheck и устраните все предупреждения:
shellcheck ваш_скрипт.sh
- Комментарии в коде пишутся на русском языке.
- Используйте говорящие имена переменных в нижнем регистре со знаком подчёркивания (
image_name,report_file). - Выводите сообщения об ошибках в
stderr:echo "Ошибка: файл не найден" >&2
Перед открытием pull request вручную проверьте изменённый скрипт на реальном или тестовом Docker-окружении. Убедитесь, что:
- скрипт отрабатывает штатный сценарий без ошибок;
- граничные случаи (пустой ввод, несуществующий образ, отсутствие прав) обрабатываются с понятным сообщением и ненулевым кодом выхода;
shellcheckне выдаёт предупреждений.
Автор и мейнтейнер проекта — Aleksei Blinov.